'use client'; import { useEffect, useMemo, type ReactNode } from 'react'; import dynamic from 'next/dynamic'; import { CheckoutPiece } from '@akinon/pz-theme/src/chrome/checkout-piece'; import { isThemeEditorDesigner } from '@akinon/pz-theme/src/chrome/checkout-pieces'; import { useAppDispatch } from '@akinon/next/redux/hooks'; import { resetCheckoutState } from '@akinon/next/redux/reducers/checkout'; import { useFetchCheckoutQuery, useResetCheckoutStateQuery } from '@akinon/next/data/client/checkout'; import { useRouter, useLocalization } from '@akinon/next/hooks'; import { Button, LoaderSpinner } from '@theme/components'; import { ROUTES } from '@theme/routes'; import settings from '@theme/settings'; import { getCheckoutVariant, UNIFIED_VARIANTS } from '@theme/views/checkout/variants/registry'; import { CheckoutOnePageSkeleton } from '@theme/views/checkout/variants/one-page/skeletons'; import { useResolvedCheckoutConfig } from '@theme/views/checkout/variants/use-resolved-config'; const Checkout = () => { const { t } = useLocalization(); const router = useRouter(); const dispatch = useAppDispatch(); const { data: indexData, isLoading: isResetStateLoading } = useResetCheckoutStateQuery(null); const { data: checkoutData, isLoading: isCheckoutLoading, isError, refetch: refetchCheckout } = useFetchCheckoutQuery(null, { refetchOnMountOrArgChange: true, skip: isResetStateLoading || !indexData }); const { variantId, options: variantOptions } = useResolvedCheckoutConfig(); const CheckoutAuth = useMemo( () => dynamic(() => import('@theme/views/checkout/auth')), [] ); const CheckoutVariant = useMemo( () => getCheckoutVariant(variantId), [variantId] ); useEffect(() => { return () => { dispatch(resetCheckoutState()); }; }, []); // eslint-disable-line react-hooks/exhaustive-deps // In unified mode the basket lives inside the checkout page and the basket // page auto-redirects here while it has items — following the backend's // basket redirect would bounce between the two pages forever. Check the // settings.js baseline as well, since the basket page redirects based on it // even when the async theme-settings override resolves to another variant. const baselineVariant = (settings as { checkout?: { variant?: string } }) ?.checkout?.variant; const isUnifiedCheckout = UNIFIED_VARIANTS.has(variantId) || UNIFIED_VARIANTS.has(baselineVariant ?? ''); // The designer canvas edits the checkout page itself — an empty test basket // must never navigate the iframe to the basket page, or the composition // being authored disappears mid-edit. Live keeps the redirect untouched. if ( !isUnifiedCheckout && checkoutData?.redirect_url?.includes('basket') && !isThemeEditorDesigner() ) { router.push(ROUTES.BASKET); return null; } // One stable CheckoutPiece instance hosts every gate below: the latch runs // once, and the loading-to-variant transition is a child swap under the same // (possibly portaled) position — no remounts mid-session. let body: ReactNode; if (checkoutData?.template_name === 'orders/index.html') { body = (
); } else if (isError) { body = (
{t('checkout.error.title')}
); } else if (isResetStateLoading || isCheckoutLoading) { body = variantId === 'multi-step' ? (
) : ( ); } else { body = ; } return {body}; }; export default Checkout;